#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>  /* for sockaddr_in and inet_addr() */

#define N_ROUTINE 7
#define STR_LEN 5

int main()
{
    int                 sockFd              ;
    int                 connectFd           ;
    int                 i                   ;
    int                 backlog = 2         ;
    size_t              bytesRcv = 0        ;
    size_t              totalBytesRcv = 0   ;
    size_t              totalBytesSnt = 0   ;
    size_t              bytesSnt      = 0   ;
    socklen_t           clientAddrSize      ;
    struct sockaddr_in  addr                ;
    struct sockaddr_in  clientAddr          ;
    char                sendBuf[] = "Hello" ;
    char                recvBuf[200]        ;

    sockFd = socket(AF_INET,        /*  Specifies the communications domain in which a socket is to be created                          */
                   SOCK_STREAM ,    /*  Specifies the type of socket to be created.                                                     */
                   IPPROTO_TCP);    /*  Specifies a particular protocol to be used with the socket. Specifying a protocol of 0 causes
                                        socket() to use an unspecified default protocol appropriate for the requested socket type.      */
    if(sockFd == -1)
    {
        perror("socket");
        return 1;
    }

    /* Construct the server sockaddr_in structure */
    memset(&addr, 0, sizeof(addr));                 /* Clear struct */
    addr.sin_family = AF_INET;                      /* Internet/IP  */
    addr.sin_addr.s_addr =inet_addr("10.0.0.102");   /* IP address   */
    addr.sin_port = 7;                              /* server port  */

    if(bind(sockFd,                             /*  socket file descriptor                                  */
            (struct sockaddr *)&addr,           /*  assigns the address specified to the socket             */
            sizeof(struct sockaddr_in)) == -1)  /*  specifies the size, in bytes, of the address structure  */
    {
        perror("bind");
        close(sockFd);
        return 1;
    }

    if(listen(sockFd, backlog))
    {
        perror("listen");
        close(sockFd);
        return 1;
    }

    clientAddrSize = sizeof(struct sockaddr_in);
    connectFd = accept(sockFd,                      /*  the binding socket fd       */
                 (struct sockaddr *) &clientAddr,   /*  gets the client addr struct */
                 &clientAddrSize);                  /*  size of the excpted struct  */
    if (connectFd == -1)
    {
        perror("accept");
        close(sockFd);
        return 1;
    }

    for(i = 0; i < N_ROUTINE; ++i)
    {
        totalBytesRcv = 0;
        totalBytesSnt = 0;
        while(totalBytesSnt < STR_LEN)
        {
            if((bytesSnt = send(connectFd, sendBuf + totalBytesSnt, STR_LEN - totalBytesSnt , 0)) == -1)
            {
                perror("send");
            }
            totalBytesSnt += bytesSnt;
        }

        while(totalBytesRcv < STR_LEN )
        {
            if((bytesRcv = recv(connectFd, recvBuf + totalBytesRcv, STR_LEN - totalBytesRcv, 0)) <= 0)
            {
                perror("recv");
                return 1;
            }
            totalBytesRcv += bytesRcv;
        }
        *(recvBuf + STR_LEN) = '\0';
        printf("%s\n", recvBuf);
    }

    close(sockFd);
    close(connectFd);

    return 0;
}



